#ifndef _sdl_indexmap_h_
#define _sdl_indexmap_h_

#include "sdl_debug.h"
#include "sdl_prim.h"
#include "sdl_my_opengl.h"
#include <vector>

#ifndef BUFFER_OFFSET
#define BUFFER_OFFSET(i) ((char*)NULL + (i))
#endif

namespace sdl_graphic {
};

class indexmap : public sdl_prim,
depends<sdl_debug::debug> {
    friend class sdl_graphic::renderer;
    unsigned int * data;
    GLuint vbo;
    int start, m;
    bool lock;
    bool vbo_managed;
    bool vbo_update;
public:

    indexmap(unsigned int * buffer, int _start, int _end) : sdl_prim(buffer == NULL ? "primary indexmap" : "mapping indexmap") {
        _msg("indexmap", 6, "tworzenie mapy indeksów " << name());
        vbo = 0;
        m = _end - _start + 1;
        start = _start;
        vbo_managed = vbo_update = false;
        if (buffer != NULL) {
            data = buffer;
            lock = false;
        } else {
            data = new unsigned int[m];
            lock = true;
        }
    }
    ///mapowanie danych ale NIE mapowanie VBO!!!

    indexmap(const indexmap & s, int sstart, int ssend) : sdl_prim("mapping indexmap") {
        vbo = 0;
        start = s.start + sstart;
        m = ssend - sstart + 1;
        lock = false;
        vbo_managed = vbo_update = false;
        data = s.data;
    }

    /*
    indexmap(const indexmap & s){
            lock=false;
            start=s.start;
            m=s.m;
            vbo=0;
            vbo_managed=false;
            vbo_update=false;
            data=s.data;
    }*/
    indexmap operator()(int s, int e) {
        return indexmap(*this, s, e);
    }

    indexmap range(int s, int e) {
        return (*this)(s, e);
    }

    virtual ~indexmap() {
        remove_vbo();
        if (lock && data != NULL) {
            delete [] data;
        }
    }

    void create_vbo() {
        if (vbo_managed)
            return;

        glGenBuffers(1, &vbo);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, size_bytes(), data, GL_STREAM_DRAW);
        vbo_managed = true;

    }

    void remove_vbo() {
        if (!vbo_managed)
            return;
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, size_bytes(), NULL, GL_STREAM_DRAW);
        glDeleteBuffers(1, &vbo);
    }

    void update_vbo() {
        if (!vbo_managed)
            return;
        if (!vbo_update)
            return;
        void * buffer;
        GLuint target = GL_ELEMENT_ARRAY_BUFFER;

        glBindBuffer(target, vbo);
        glBufferData(target, size_bytes(), NULL, GL_STREAM_DRAW);
        buffer = glMapBuffer(target, GL_WRITE_ONLY);

        std::memcpy(buffer, data, size_bytes());
        glBindBuffer(target, vbo);
        glUnmapBuffer(target);
        buffer = NULL;
        vbo_update = false;
    }

    int size_bytes() {
        return m * sizeof (unsigned int);
    }

    int size() {
        return m;
    }

    void touch() {
        vbo_update = true;
    }

    /*
    operator const unsigned int *() const {
            return data;
    }*/
    const unsigned int * get() const {
        return data;
    }

    unsigned int & operator[](unsigned int k) {
        if (k < m) {
            return data[start + k];
        } else
            _err("indexmap", "błąd zakresu: " << k << " leży poza końcem " << m);
    }
};



#endif //_sdl_indexmap_h_


